package org.budo.druid.filter.log.slf4j;

import java.sql.SQLException;
import java.util.ArrayList;
import java.util.List;

import org.budo.support.javax.sql.util.JdbcUtil;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import com.alibaba.druid.filter.FilterChain;
import com.alibaba.druid.filter.logging.Slf4jLogFilter;
import com.alibaba.druid.proxy.jdbc.CallableStatementProxy;
import com.alibaba.druid.proxy.jdbc.JdbcParameter;
import com.alibaba.druid.proxy.jdbc.PreparedStatementProxy;
import com.alibaba.druid.proxy.jdbc.StatementProxy;
import com.alibaba.druid.sql.SQLUtils;
import com.alibaba.druid.sql.SQLUtils.FormatOption;

import lombok.extern.slf4j.Slf4j;

/**
 * @author li
 * @version 1 (2015年12月21日 下午3:53:24)
 * @since Java7
 * @see com.alibaba.druid.filter.logging.Slf4jLogFilter
 */
@Slf4j
public class BudoSlf4jLogFilter extends Slf4jLogFilter {
    private static final Logger statementLogger = LoggerFactory.getLogger("BudoSlf4jLogFilter.statementLogger");

    private static final FormatOption statementSqlFormatOption_2 = new FormatOption(false, true);

    private static final String _stmtId(StatementProxy statement) {
        StringBuffer buf = new StringBuffer();
        if (statement instanceof CallableStatementProxy) {
            buf.append("cstmt-");
        } else if (statement instanceof PreparedStatementProxy) {
            buf.append("pstmt-");
        } else {
            buf.append("stmt-");
        }

        buf.append(statement.getId());
        return buf.toString();
    }

    @Override
    public void preparedStatement_setNull(FilterChain chain, PreparedStatementProxy statement, int parameterIndex, int sqlType) throws SQLException {
        try {
            super.preparedStatement_setNull(chain, statement, parameterIndex, sqlType);
        } catch (SQLException e) {
            log.error("#53 sql=" + statement.getSql() + ", parameters=" + statement.getParameters() + ", parameterIndex=" + parameterIndex + ", statement=" + statement + ", e=" + e, e);
            throw e;
        }
    }

    @Override
    public void preparedStatement_setNull(FilterChain chain, PreparedStatementProxy statement, int parameterIndex, int sqlType, String typeName) throws SQLException {
        try {
            super.preparedStatement_setNull(chain, statement, parameterIndex, sqlType, typeName);
        } catch (SQLException e) {
            log.error("#53 sql=" + statement.getSql() + ", parameters=" + statement.getParameters() + ", parameterIndex=" + parameterIndex + ", statement=" + statement + ", e=" + e, e);
            throw e;
        }
    }

    @Override
    protected void statement_executeErrorAfter(StatementProxy statement, String sql, Throwable error) {
        boolean statementLogErrorEnabled = this.isStatementLogErrorEnabled();
        if (!statementLogErrorEnabled) {
            return;
        }

        boolean statementExecutableSqlLogEnable = this.isStatementExecutableSqlLogEnable();
        if (!statementExecutableSqlLogEnable) {
            this.statementLogError("#44 {conn-" + statement.getConnectionProxy().getId() + ", " + _stmtId(statement) + "} execute error. " + sql, error);
            return;
        }

        int parametersSize = statement.getParametersSize();
        if (parametersSize < 1) {
            this.statementLogError("#50 {conn-" + statement.getConnectionProxy().getId() + ", " + _stmtId(statement) + "} execute error. " + sql, error);
            return;
        }

        List<Object> parameters = new ArrayList<Object>(parametersSize);
        for (int i = 0; i < parametersSize; ++i) {
            JdbcParameter jdbcParam = statement.getParameter(i);
            parameters.add(jdbcParam != null ? jdbcParam.getValue() : null);
        }

        String dbType = statement.getConnectionProxy().getDirectDataSource().getDbType();
        String formattedSql = SQLUtils.format(sql, dbType, parameters, statementSqlFormatOption_2);

        // SQL 太长了 里面有图片
        if (null != formattedSql && formattedSql.length() > 1024) {
            formattedSql = formattedSql.substring(0, 1024) + " ... ";
        }

        // stackTraceWhenError is false
        if (JdbcUtil.isTableNotExist(error) //
                || JdbcUtil.isDataTooLong(error) //
                || JdbcUtil.isIncorrectStringValue(error)) {
            statementLogger.error("#61 e=" + error + ", {conn-" + statement.getConnectionProxy().getId() + ", " + _stmtId(statement) + "} execute error. " + formattedSql + ", e=" + error); // 打印简单异常信息
        } else {
            statementLogger.error("#61 e=" + error + ", {conn-" + statement.getConnectionProxy().getId() + ", " + _stmtId(statement) + "} execute error. " + formattedSql, error); // 打印异常堆栈
        }
    }
}